6200 // The I/O APIC manages hardware interrupts for an SMP system.
6201 // http://www.intel.com/design/chipsets/datashts/29056601.pdf
6202 // See also picirq.c.
6203 
6204 #include "types.h"
6205 #include "defs.h"
6206 #include "traps.h"
6207 
6208 #define IOAPIC  0xFEC00000   // Default physical address of IO APIC
6209 
6210 #define REG_ID     0x00  // Register index: ID
6211 #define REG_VER    0x01  // Register index: version
6212 #define REG_TABLE  0x10  // Redirection table base
6213 
6214 // The redirection table starts at REG_TABLE and uses
6215 // two registers to configure each interrupt.
6216 // The first (low) register in a pair contains configuration bits.
6217 // The second (high) register contains a bitmask telling which
6218 // CPUs can serve that interrupt.
6219 #define INT_DISABLED   0x00010000  // Interrupt disabled
6220 #define INT_LEVEL      0x00008000  // Level-triggered (vs edge-)
6221 #define INT_ACTIVELOW  0x00002000  // Active low (vs high)
6222 #define INT_LOGICAL    0x00000800  // Destination is CPU id (vs APIC ID)
6223 
6224 volatile struct ioapic *ioapic;
6225 
6226 // IO APIC MMIO structure: write reg, then read or write data.
6227 struct ioapic {
6228   uint reg;
6229   uint pad[3];
6230   uint data;
6231 };
6232 
6233 static uint
6234 ioapicread(int reg)
6235 {
6236   ioapic->reg = reg;
6237   return ioapic->data;
6238 }
6239 
6240 static void
6241 ioapicwrite(int reg, uint data)
6242 {
6243   ioapic->reg = reg;
6244   ioapic->data = data;
6245 }
6246 
6247 
6248 
6249 
6250 void
6251 ioapicinit(void)
6252 {
6253   int i, id, maxintr;
6254 
6255   if(!ismp)
6256     return;
6257 
6258   ioapic = (volatile struct ioapic*)IOAPIC;
6259   maxintr = (ioapicread(REG_VER) >> 16) & 0xFF;
6260   id = ioapicread(REG_ID) >> 24;
6261   if(id != ioapicid)
6262     cprintf("ioapicinit: id isn't equal to ioapicid; not a MP\n");
6263 
6264   // Mark all interrupts edge-triggered, active high, disabled,
6265   // and not routed to any CPUs.
6266   for(i = 0; i <= maxintr; i++){
6267     ioapicwrite(REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i));
6268     ioapicwrite(REG_TABLE+2*i+1, 0);
6269   }
6270 }
6271 
6272 void
6273 ioapicenable(int irq, int cpunum)
6274 {
6275   if(!ismp)
6276     return;
6277 
6278   // Mark interrupt edge-triggered, active high,
6279   // enabled, and routed to the given cpunum,
6280   // which happens to be that cpu's APIC ID.
6281   ioapicwrite(REG_TABLE+2*irq, T_IRQ0 + irq);
6282   ioapicwrite(REG_TABLE+2*irq+1, cpunum << 24);
6283 }
6284 
6285 
6286 
6287 
6288 
6289 
6290 
6291 
6292 
6293 
6294 
6295 
6296 
6297 
6298 
6299 
